import "gl-matrix";

import { mat4, vec3, vec4 } from "gl-matrix";
import { cubeData, getFloat32Array, initTexture } from "./helper";

let gl: WebGLRenderingContext = null;
let canvas: HTMLCanvasElement = null;
let angle = 0;
var elapsedTime: number = 0;
var lastRenderTime: number = 0;
var viewMatrix: mat4 = mat4.create();
var cameraAngleAroundY = 0;
var cameraAngleAroundX = 0;
var cameraDistanceFromTarget = 3;
let texture: WebGLTexture = null;
var program: WebGLProgram;
var vertexShader: WebGLShader;
var fragmentShader: WebGLShader;
let projection: mat4 = null;
//键盘变量
let varTransZ = 0;
let varTransX = 0;
let varTransY = 0;
let varRotY = 0;
let varRotX = 0;
let varRotZ = 0;
let varScale = 1;
let mouseDown = false;
const vertexShaderCode =
  "attribute vec3 position;" +
  "attribute vec4 inColor;" +
  "attribute vec2 inUV;" +
  "uniform mat4 projection;" +
  "varying vec4 outColor;" +
  "varying vec2 outUV;" +
  "void main() {" +
  "gl_Position = projection * vec4(position,1.0);" +
  "outColor = inColor;" +
  "outUV = inUV;" +
  "}";
const fragmentShaderCode =
  "precision mediump float;" +
  "varying vec4 outColor;" +
  "varying vec2 outUV;" +
  "uniform sampler2D texture;" +
  "void main() {" +
  "gl_FragColor = texture2D(texture,outUV);" +
  // "gl_FragColor = vec4(0.8,1.0,1.0,1.0);"+
  "}";
// 准备WebGL的绘制上下文
function prepare() {
  canvas = document.createElement("canvas");
  canvas.width = window.innerWidth;
  canvas.height = window.innerHeight - 20;
  canvas.style.width = "" + canvas.width;
  canvas.style.height = "" + canvas.height;
  canvas.style.overflow = "hidden";
  document.body.append(canvas);
  window.onresize = function (evt: Event) {
    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;
    canvas.style.width = "" + canvas.width;
    canvas.style.height = "" + canvas.height;
  };
  gl = canvas.getContext("webgl");
  gl.enable(gl.DEPTH_TEST);
  lastRenderTime = new Date().getTime();
}

// 准备WebGL需要使用的素材
function webglPrepare() {
  prepareVertexData();
  createProgram();
}

var vertexData: WebGLBuffer;
function prepareVertexData() {
  // Prepare Vertex Data

  let vertices: Float32Array = getFloat32Array(cubeData);

  // 在GPU上为顶点数据开辟空间
  vertexData = gl.createBuffer();
  // 将上面开辟的空间进入编辑模式
  gl.bindBuffer(gl.ARRAY_BUFFER, vertexData);
  // 向上面开辟的空间写入数据
  gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
}

function createProgram() {
  program = gl.createProgram();

  vertexShader = compileShader(vertexShaderCode, gl.VERTEX_SHADER);
  fragmentShader = compileShader(fragmentShaderCode, gl.FRAGMENT_SHADER);
  gl.attachShader(program, vertexShader);
  gl.attachShader(program, fragmentShader);
  gl.linkProgram(program);

  if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
    console.log(
      "Unable to initialize the shader program: " +
        gl.getProgramInfoLog(program)
    );
  }
  return program;
}

function compileShader(shaderSrc: string, shaderType: number): WebGLShader {
  let shader = gl.createShader(shaderType);
  gl.shaderSource(shader, shaderSrc);
  gl.compileShader(shader);
  if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
    console.log(
      "An error occurred compiling the shaders: " + gl.getShaderInfoLog(shader)
    );
    gl.deleteShader(shader);
    return null;
  }
  return shader;
}
function renderColor() {
  const inColorLoc = gl.getAttribLocation(program, "inColor");
  gl.enableVertexAttribArray(inColorLoc);
  gl.vertexAttribPointer(inColorLoc, 4, gl.FLOAT, false, 4 * 9, 4 * 3);
}
function renderTexture() {
  const textureUniform = gl.getUniformLocation(program, "texture");
  gl.activeTexture(gl.TEXTURE0);
  gl.bindTexture(gl.TEXTURE_2D, texture);
  gl.uniform1i(textureUniform, 0);

  const attrUV = gl.getAttribLocation(program, "inUV");
  gl.enableVertexAttribArray(attrUV);
  gl.vertexAttribPointer(attrUV, 2, gl.FLOAT, false, 4 * 9, 4 * 7);
}
function degToRadian(deg: number): number {
  return (deg * Math.PI) / 180;
}
function renderCube() {
  const mvp = mat4.create();
  const matTrans = mat4.create(); //平移
  const matRot = mat4.create(); //旋转
  const matModel = mat4.create();
  const matScale = mat4.create();
  const positionLoc = gl.getAttribLocation(program, "position");
  const uniformLoc = gl.getUniformLocation(program, "projection");
  const rotaAxis = vec3.create();
  vec3.set(rotaAxis, 0.5, 0.5, -0.5);
  // angle++;
  // angle=10;
  mat4.identity(matTrans);
  mat4.identity(matRot);
  mat4.identity(matModel);
  mat4.identity(matScale);
  {
    const matRotY = mat4.create();
    const matRotX = mat4.create();
    const matRotZ = mat4.create();
    mat4.identity(matRotY);
    mat4.identity(matRotX);
    mat4.identity(matRotZ);
    mat4.rotateX(matRotX, matRotX, degToRadian(varRotX));
    mat4.rotateY(matRotY, matRotY, degToRadian(varRotY));
    mat4.rotateZ(matRotZ, matRotZ, degToRadian(varRotZ));
    mat4.multiply(matRot, matRotY, matRotX);
    // mat4.multiply(matRot, matRot, );
    mat4.multiply(matRot, matRot, matRotZ);
  }
  mat4.scale(matScale, matScale, [varScale, varScale, varScale]);
  //平移
  mat4.translate(matTrans, matTrans, [varTransX, varTransY, varTransZ-5]);
  if (varTransY > 0) {
    varTransY -= 0.01;
  }
  mat4.rotate(matRot, matRot, degToRadian(0), [0.5, 0.5, -0.5]);
  mat4.multiply(matModel, matTrans, matRot);
  mat4.multiply(matModel, matModel, matScale);
  mat4.multiply(mvp, projection, matModel);
  gl.enableVertexAttribArray(positionLoc);
  gl.vertexAttribPointer(positionLoc, 3, gl.FLOAT, false, 4 * 9, 0);
  gl.uniformMatrix4fv(uniformLoc, false, mvp);
}

function render() {
  let now = new Date().getTime();
  let delta = now - lastRenderTime;
  lastRenderTime = now;
  elapsedTime += delta;

  gl.viewport(0, 0, canvas.width, canvas.height);
  projection = mat4.create();
  mat4.perspective(
    projection,
    (60 * Math.PI) / 180,
    canvas.width / canvas.height,
    0.01,
    1000
  );
  gl.clearColor(0, 0, 0, 1.0);
  gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
  gl.enable(gl.DEPTH_TEST);
  gl.useProgram(program);
  gl.bindBuffer(gl.ARRAY_BUFFER, vertexData);
  renderCube();
  renderTexture();
  renderColor();
  gl.drawArrays(gl.TRIANGLES, 0, 36);

  requestAnimationFrame(render);
}
function onKeyDown(event: KeyboardEvent) {
  console.log("key");
  const key = event.key.toUpperCase();
  switch (key) {
    case "W":
      varTransZ -= 0.1;
      break;
    case "A":
      varTransX -= 0.1;
      break;
    case "S":
      varTransZ += 0.1;
      break;
    case "D":
      varTransX += 0.1;
      break;
    case " ":
      varTransY += 1;
      break;
  }
}
function onMousemove(event: MouseEvent) {
  if (mouseDown) {
    const { movementX, movementY } = event;
    if (movementX !== 0 && movementY !== 0) {
      varRotZ = varRotZ + 1 * movementX * movementY;
    } else if (movementX) {
      varRotY = varRotY + 1 * movementX;
    } else if (movementY) {
      varRotX = varRotX + 1 * movementY;
    }
  }
}
function onWheelChange(event: WheelEvent) {
  const scale = event.deltaY > 0 ? -1 : 1;
  varScale = varScale + 0.1 * scale;
  if (varScale <= 0) {
    varScale = 0;
  }
}
window.onload = () => {
  // 主流程

  prepare();
  webglPrepare();

  initTexture(gl, "./wall1.png").then((txure) => {
    texture = txure;
    render();
  });

  document.onkeydown = onKeyDown;
  canvas.onmousedown = () => {
    mouseDown = true;
  };
  canvas.onmouseup = () => {
    mouseDown = false;
  };
  canvas.onwheel = onWheelChange;
  canvas.onmousemove = onMousemove;
};
